Skip to content

Add Python project base template#2

Merged
samhodgkinson merged 2 commits into
mainfrom
claude/python-docker-template-QWs3s
Jun 6, 2026
Merged

Add Python project base template#2
samhodgkinson merged 2 commits into
mainfrom
claude/python-docker-template-QWs3s

Conversation

@samhodgkinson

Copy link
Copy Markdown
Owner

Summary

  • Multi-stage Dockerfile (dev for dev containers / testing, prod for deployment) using ghcr.io/astral-sh/uv as base
  • pyproject.toml with uv, Ruff, Mypy (strict), Pytest, Bandit, pip-audit configured in one file
  • VS Code settings, recommended extensions, and debug launch configs wired up for Ruff + Mypy + pytest
  • Dev container built from the dev Dockerfile target with non-root devuser, named .venv volume, and auto-sync on create
  • GitHub Actions CI: lint (Ruff + Mypy), tests with coverage, pip-audit dependency scan, Docker build (with per-target GHA cache)
  • GitHub Actions CodeQL: Python SAST on push/PR/weekly schedule
  • CLAUDE.md AI context + .claude/commands/ slash commands (/test, /lint, /security, /build)
  • uv.lock committed for reproducible installs

Changes reviewed and fixed before merge

  • pythonpath = ["src"] added to pytest config so bare pytest works without editable install
  • Pylance type checking set to "off" to defer entirely to the mypy extension (was "basic", inconsistent with strict = true in mypy)
  • Coverage flags removed from addopts — passed explicitly in CI only, so local pytest runs aren't slowed by coverage every time
  • Bandit removed from CI — CodeQL covers the same SAST categories with better data-flow analysis; bandit remains available locally via uv run bandit
  • Docker GHA cache scopes added (scope=dev / scope=prod) to prevent the two build steps overwriting each other's cache
  • enable-cache: true added to all setup-uv steps
  • Dead targets = ["src"] removed from [tool.bandit] (not a valid pyproject.toml key for bandit)
  • Confusing dev compose service removed — it was just a pytest runner with a misleading name
  • Build-time uv sync removed from the dev Dockerfile stage — the .venv named volume always shadowed it; uv run auto-syncs on first use instead
  • devuser (uid 1000) added to the dev stage; devcontainer now runs as non-root
  • LICENSE added to the builder stage COPY so hatchling can read it during uv sync --no-dev
  • Redundant mypy flags (warn_return_any, warn_unused_configs) removed — already implied by strict = true

Test plan

  • CI passes (lint, test, security, docker build)
  • CodeQL passes
  • Open repo in VS Code → "Reopen in Container" builds and installs correctly
  • uv run pytest passes locally after uv sync --all-groups
  • docker compose run --rm test runs the test suite

https://claude.ai/code/session_01TiXyp1vCmxNP2ewP4s1TGH


Generated by Claude Code

claude added 2 commits June 5, 2026 23:06
hatchling reads the LICENSE file declared in pyproject.toml
(`license = { file = "LICENSE" }`) at build time. The builder stage
only had pyproject.toml and uv.lock, causing:
  OSError: License file does not exist: LICENSE

https://claude.ai/code/session_01TiXyp1vCmxNP2ewP4s1TGH
hatchling reads both README.md and LICENSE at package build time
(declared in pyproject.toml as readme and license fields).

Split the builder stage into two steps following uv's recommended
Docker pattern:
  1. uv sync --no-dev --no-install-project  →  external deps only
     (cached layer; invalidated only when pyproject.toml/uv.lock change)
  2. Copy README.md + LICENSE + src/, then uv sync --no-dev
     →  builds and installs the project with all required files present

This also gives better layer caching: adding a dependency rebuilds
step 1, changing source only rebuilds step 2.

https://claude.ai/code/session_01TiXyp1vCmxNP2ewP4s1TGH
@samhodgkinson samhodgkinson merged commit 67f3475 into main Jun 6, 2026
6 checks passed
@samhodgkinson samhodgkinson deleted the claude/python-docker-template-QWs3s branch June 6, 2026 15:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants